﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OverStore.Configuration.Builder;
using System.Data.SqlServerCe;
using OverStore.Configuration.TableStore;
using OverStore.Configuration.TableStore.Mappings;

namespace OverStore.TutorialAsTest.UnitTest.TableStore
{
    /// <summary>
    /// Contains set of test checks TableStore configuration.
    /// </summary>
    [TestClass]
    public class TableStoreTest
    {
        /// <summary>
        /// Test class contains data from simple table (without foreign keys).
        /// </summary>
        class ItemType
        {
            public int Type { get; set; }

            public string Name { get; set; }

            public string Description { get; set; }
        }

        private static IPersistenceSessionFactory CreateItemTypeConfig()
        {
            return new OverStoreFluentBuilder()
                .LogToConsole()
                .ConnectToDatabase<SqlCeConnection>(TestHelper.MyMoneyConnectionString)
                    .WithRepository<ItemType>(
                            new TableStore<ItemType, int>
                            {
                                PKColumn = "Type",
                                Columns = new List<IColumnMapping<ItemType>>
                                {
                                    new ColumnMapping<ItemType, int> { ColumnName = "Type" },
                                    new ColumnMapping<ItemType, string> { ColumnName = "Name" },
                                    new ColumnMapping<ItemType, string> { ColumnName = "Description" }
                                }
                            })
                .EndConfiguration();

        }

        [TestMethod]
        public void TableStore_GetItemType()
        {
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var itemType = session.GetByIdentifier<ItemType, int>(1);
                Assert.AreEqual(1, itemType.Type);
                Assert.AreEqual("Product or Service", itemType.Name);
                Assert.IsNull(itemType.Description);
            }
        }

        [TestMethod]
        public void TableStore_AddNewItemType()
        {
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var newItemType = new ItemType { Type = 1001, Description = "Description", Name = "NewItemType" };
                session.Add(newItemType);
                session.SaveAll();
            }
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var newItemType = session.GetByIdentifier<ItemType, int>(-1);
                Assert.AreEqual(-1, newItemType.Type);
                Assert.AreEqual("NewItemType", newItemType.Name);
                Assert.AreEqual("Description", newItemType.Description);
            }
        }

        [TestMethod]
        public void TableStore_UpdateItemType()
        {
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var itemType = session.GetByIdentifier<ItemType, int>(2);
                Assert.AreEqual(2, itemType.Type);
                Assert.AreEqual("Currency", itemType.Name);
                itemType.Type = 5;
                itemType.Name = "updated";
                session.SaveAll();
            }
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var itemType = session.GetByIdentifier<ItemType, int>(2);
                Assert.AreEqual(2, itemType.Type);
                Assert.AreEqual("updated", itemType.Name);
                itemType.Name = "Currency";
                session.SaveAll();
            }
        }

        [TestMethod]
        public void TableStore_AttachItemType_Existing()
        {
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var existing = session.GetByIdentifier<ItemType, int>(1);
                Assert.AreEqual(1, existing.Type);
                Assert.AreEqual("Product or Service", existing.Name);
                Assert.IsNull(existing.Description);

                var detached = new ItemType { Type = 1, Name = "Attached", Description = "Attached" };
                var attached = session.Attach(detached, AttachOptions.DoNotCheckStorage);

                Assert.AreSame(existing, attached);
                Assert.AreEqual(1, existing.Type);
                Assert.AreEqual("Attached", existing.Name);
                Assert.AreEqual("Attached", existing.Description);
                session.SaveAll();
            }
            using (var session = CreateItemTypeConfig().CreateSession())
            {
                var updated = session.GetByIdentifier<ItemType, int>(1);
                Assert.AreEqual(1, updated.Type);
                Assert.AreEqual("Attached", updated.Name);
                Assert.AreEqual("Attached", updated.Description);
                updated.Name = "Product or Service";
                updated.Description = null;
                session.SaveAll();
            }
        }

        class TestItem
        {
            public string Name { get; set; }

            public DateTime CreatedAtDateTime { get; set; }

            public TestItem Referenced { get; set; }
        }

        private static IPersistenceSessionFactory CreateTestItemConfig()
        {
            return new OverStoreFluentBuilder()
                .LogToConsole()
                .ConnectToDatabase<SqlCeConnection>("Data Source = 'TestDb.sdf'")
                .WithRepository(new TableStore<TestItem, int>
                    {
                        TableName = "testTable2",
                        PKColumn = "Id",
                        IsPrimaryKeyGeneratedByDatabase = true,
                        Columns = new List<IColumnMapping<TestItem>>
                        {
                            new ColumnMapping<TestItem, string> { ColumnName = "Name" },
                            new ColumnMapping<TestItem, DateTime> { ColumnName = "CreatedAt", PropertyName = "CreatedAtDateTime" },
                            new ReferenceMapping<TestItem, TestItem, int> { ColumnName = "RefId", PropertyName = "Referenced" }
                        }
                    })
                .EndConfiguration();
        }

        [TestMethod]
        public void TableStore_GetTestItem()
        {
            using (var session = CreateTestItemConfig().CreateSession())
            {
                var item = session.GetByIdentifier<TestItem, int>(3);
                Assert.AreEqual("ValueSubTwo", item.Name);
                Assert.AreEqual(new DateTime(2009, 10, 1, 0, 0, 0), item.CreatedAtDateTime);
                Assert.IsNotNull(item.Referenced);

                Assert.AreEqual("ValueSubOne", item.Referenced.Name);

                Assert.IsNotNull(item.Referenced.Referenced);
                Assert.AreEqual("ValueOne", item.Referenced.Referenced.Name);
            }
        }

        [TestMethod]
        public void TableStore_AddNewTestItem()
        {
            using (var session = CreateTestItemConfig().CreateSession())
            {
                var newItem = new TestItem
                {
                    Name = "NewlyAddedTestItem",
                    CreatedAtDateTime = new DateTime(2009, 1, 1),
                    Referenced = session.GetByIdentifier<TestItem, int>(1)
                };
                session.Add(newItem);
                session.SaveAll();
            }
            using (var session = CreateTestItemConfig().CreateSession())
            {
                var savedItem = session.GetByIdentifier<TestItem, int>(4);
                Assert.AreEqual("NewlyAddedTestItem", savedItem.Name);
                Assert.AreEqual(new DateTime(2009, 1, 1), savedItem.CreatedAtDateTime);
                Assert.IsNotNull(savedItem.Referenced);
                Assert.AreEqual("ValueOne", savedItem.Referenced.Name);
                session.MarkAsDeleted(savedItem);
                session.SaveAll();
            }
        }
    }
}
